from xml.dom import minidom, Node
from XmlCppClassGenerator.OutputStreams import OutputStream
import codecs

## Class allowing to load a XML file. It can also perform check on the
# root element (to be sure that the correct file is read). A generic
# method to read the data from the XML is implemented, as well as a
# generic way to get back the information.
#
# Inherits from OutputStreams.OutputStream, in order to get nice
# output.
#
# @author Johan "Solo" Luisier
# @date November 2011
class _BaseReader( OutputStream ) :
    ## Contructor.
    # Initialises the parent class, the file name and the DOM
    # document.
    #
    # @param[in] self reference on the calling instance.
    # @param[in] fileName name of the XML file to read.
    def __init__( self, fileName ) :
        OutputStream.__init__( self )
        ## Name of the XML file which will be read.
        self.__XmlFileName = fileName
        ## Document node of the XML file.
        self.__XmlDomDocument = minidom.parse( self.__XmlFileName )
        ## Root element node from the parsed XML file.
        self.__XmlDomRoot = self.__XmlDomDocument.documentElement
    ## Allows to access __XmlDomRoot.
    #
    # @param[in] self reference on the calling instance.
    #
    # @return a reference on __XmlDomRoot.
    def _getXmlDomRoot( self ) :
        return self.__XmlDomRoot
    ## Checks that the root element is the expected one.
    #
    # @param[in] self reference on the calling instance.
    # @param[in] expectedNodeName name of the expected root element.
    #
    # @return \e True if the root element name is the expected one, \e
    # False if not.
    def checkRootNode( self, expectedNodeName ) :
        if ( self.__XmlDomRoot.nodeName != expectedNodeName ) :
            message = "The file" + self.__XmlFileName + "seems not to have the"
            message += "wanted syntax, the first element has name: "
            message += self.__XmlDomRoot.nodeName
            self.fatal( message )
            return False
        else :
            return True
    ## Loads the needed information from the xml file into the class.
    #
    # @param[in] self reference on calling instance.
    # @param[in] nodeList list of nodes which are related to the same
    # kind of information.
    # @param[in] refList list of wanted elements.
    # @param[in,out] dictList list of dictionnaries which will contain
    # the gathered information.
    #
    # @return \e True if every piece of information could be
    # retrieved, \e False if not.
    def _loadInformation( self, nodeList, refList, dictList ) :
        for theNode, theRef, theDict in zip( nodeList, refList, dictList ) :
            OK = True
            OK = self._loadElements( theNode, theRef, theDict )
            
            if ( not OK ) :
                return OK

            for key in theRef :
                if ( not key in theDict ) :
                    print "Missing", key, "in XML file."
                    return False

        return True
    ## Allows to load the wanted information in the correct
    # dictionnary. Helper function defined to reduce code duplication.
    #
    # @param[in] self reference on the calling instance.
    # @param[in] node instance of node for which the information will
    # be collected.
    # @param[in] ref list of wanted elements.
    # @param[in,out] theDict dictionnary which will contain the gathered
    # information.
    #
    # @return \e True if all the wanted pieces of information are
    # present, \e False if not.
    def _loadElements( self, node, ref, theDict ) :
        for child in node.childNodes :
            if ( not child.nodeName in ref ) :
                continue
            key = child.nodeName
            val1 = child.firstChild.nodeValue.strip()
            val2 = ""
            for ( name, value ) in child.attributes.items() :
                if ( name == "nbr" ) :
                    val2 = value
            tempDict = { child.nodeName : ( val1, val2 ) }
            theDict.update( tempDict )

        for key in ref :
            if ( not key in theDict ) :
                print "Missing", key, "in XML file."
                return False

        return True
    ## Allows to access the wanted information.
    #
    # @param[in] self reference on the calling instance.
    # @param[in] theDict dictionary containing the wanted information.
    # @param[in] key key of the wanted information.
    #
    # @return a tuple containing the wanted information and the number
    # of strings to be replaced with format().
    def _getInformation( self, theDict, key ) :
        if ( not key in theDict ) :
            return "", -1

        return theDict[ key ]
